package com.mai4j.maiadmin.support.i18n;

import org.apache.commons.lang3.StringUtils;
import org.springframework.context.i18n.LocaleContext;
import org.springframework.context.i18n.TimeZoneAwareLocaleContext;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.util.WebUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Locale;
import java.util.Objects;
import java.util.TimeZone;

public class I18nLocaleResolver extends CookieLocaleResolver {

    private final static String DEFAULT_I18N_KEY_NAME = "language";

    private final DefaultLocale defaultLocale;

    public I18nLocaleResolver(DefaultLocale defaultLocale) {
        this(DEFAULT_I18N_KEY_NAME, defaultLocale);
    }

    public I18nLocaleResolver(String name, DefaultLocale defaultLocale) {
        setCookieName(name);
        this.defaultLocale = defaultLocale;
    }

    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        parseLocaleIfNecessary(request);
        return (Locale) request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
    }

    @Override
    public LocaleContext resolveLocaleContext(final HttpServletRequest request) {
        parseLocaleIfNecessary(request);
        return new TimeZoneAwareLocaleContext() {
            @Override
            @Nullable
            public Locale getLocale() {
                return (Locale) request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
            }

            @Override
            @Nullable
            public TimeZone getTimeZone() {
                return (TimeZone) request.getAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME);
            }
        };
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
        super.setLocale(request, response, locale);
    }

    @Override
    public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, LocaleContext localeContext) {
        super.setLocaleContext(request, response, localeContext);
    }

    /**
     * 解析 Locale 信息
     *
     * @param request request
     */
    private void parseLocaleIfNecessary(HttpServletRequest request) {
        if (request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME) == null) {
            String cookieName = getCookieName();
            String language = StringUtils.defaultIfBlank(getCookie(request, cookieName), request.getHeader(cookieName));
            Locale locale = Arrays.stream(Locale.getAvailableLocales())
                    .filter(l -> Objects.equals(l.toLanguageTag(), language))
                    .findFirst()
                    .orElse(defaultLocale.get(request));
            request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME, locale);
            request.setAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME, determineDefaultTimeZone(request));
        }
    }

    /**
     * 读取Cookie值
     *
     * @param request    request
     * @param cookieName cookieName
     * @return Value
     */
    private static String getCookie(HttpServletRequest request, String cookieName) {
        Cookie cookie = WebUtils.getCookie(request, cookieName);
        return cookie == null ? null : cookie.getValue();
    }
}
